package com.brainhealth.customer.handle;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.brainhealth.common.constant.CacheConstants;
import com.brainhealth.common.core.redis.RedisCache;
import com.brainhealth.common.utils.StringUtils;
import com.brainhealth.customer.domain.Customer;
import com.brainhealth.customer.domain.SysUserEventBuriedPoint;
import com.brainhealth.customer.domain.UserEventBuriedPointParam;
import com.brainhealth.customer.mapper.SysUserEventBuriedPointMapper;
import com.brainhealth.customer.service.ISysBuriedPointService;
import com.brainhealth.customer.service.ISysUserEventBuriedPointService;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.AttributeKey;
import org.apache.logging.log4j.util.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Collection;
import java.util.Iterator;


/**
 * TextWebSocketFrame类型， 表示一个文本帧
 * @author wolong
 * @date 2020-03-28-13:47
 */
@Component
@ChannelHandler.Sharable
public class WebSocketHandler extends SimpleChannelInboundHandler<TextWebSocketFrame>
{
    private static final Logger log = LoggerFactory.getLogger(NettyServer.class);

    @Autowired
    private ISysUserEventBuriedPointService sysUserEventBuriedPointService;
    @Autowired
    private ISysBuriedPointService sysBuriedPointService;
    @Autowired
    private RedisCache redisCache;

    /**
     * 一旦连接，第一个被执行
     * @param ctx
     * @throws Exception
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx)
    {
        log.info("handlerAdded 被调用" + ctx.channel().id().asLongText());
        // 添加到channelGroup 通道组
        NettyConfig.getChannelGroup().add(ctx.channel());
    }

    /**
     * 读取数据
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg)
    {
        log.info("服务器收到消息：{}", msg.text());

        // 获取用户ID,关联channel
        JSONObject jsonObject = JSONUtil.parseObj(msg.text());
        String phone = jsonObject.getStr("phone");
        if (StringUtils.isNotEmpty(phone))
        {
            NettyConfig.getUserChannelMap().put(phone, ctx.channel());
            // 将用户ID作为自定义属性加入到channel中，方便随时channel中获取用户ID
            AttributeKey<String> key = AttributeKey.valueOf("userId");
            ctx.channel().attr(key).setIfAbsent(phone);
            // 回复消息
            ctx.channel().writeAndFlush(new TextWebSocketFrame("服务器连接成功！"));
        }
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) {
        log.info("handlerRemoved 被调用"+ctx.channel().id().asLongText());
        // 删除通道
        NettyConfig.getChannelGroup().remove(ctx.channel());
        removeUserId(ctx);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        log.info("异常：{}",cause.getMessage());
        // 删除通道
        NettyConfig.getChannelGroup().remove(ctx.channel());
        removeUserId(ctx);
        ctx.close();
    }

    /**
     * 删除用户与channel的对应关系
     * @param ctx
     */
    private void removeUserId(ChannelHandlerContext ctx)
    {
        AttributeKey<String> key = AttributeKey.valueOf("userId");
        String userId = ctx.channel().attr(key).get();
        if (Strings.isNotEmpty(userId))
        {
            Collection<String> collection = redisCache.keys(CacheConstants.CUSTOMER_TOKEN + userId + "*");
            if (collection.size() > 0)
            {
                Iterator iterator = collection.iterator();
                String tokenKey = "";
                while (iterator.hasNext())
                {
                    tokenKey = iterator.next().toString();
                }
                Customer customer = JSON.parseObject(redisCache.getCacheObject(tokenKey), Customer.class);
                if (customer != null)
                {
                    UserEventBuriedPointParam userEvent = new UserEventBuriedPointParam();
                    userEvent.setBuriedPointName("用户退出应用");
                    userEvent.setBuriedPointType(1);
                    userEvent.setEventType(1);
                    SysUserEventBuriedPoint sysUserEventBuriedPoint = sysBuriedPointService.constructorUserEventBuriedPoint(customer, userEvent);
                    sysUserEventBuriedPointService.insertSysUserEventBuriedPoint(sysUserEventBuriedPoint);
                    log.info("用户退出应用" + customer.getPhone());
                }
            }
            NettyConfig.getUserChannelMap().remove(userId);
            log.info("移除用户" + userId);
        }
    }
}